﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MyEmulators2
{
    /// <summary>
    /// 
    /// </summary>
    internal partial class Conf_DBBrowser : ContentPanel
    {
        List<ListViewItem> dbGames;
        
        Game selectedGame = null;
        bool saveSelectedGame = false;
        bool saveThumbs = false;

        ListViewItem selectedListItem = null;
        ThumbGroup itemThumbs = null;

        public Conf_DBBrowser()
        {
            InitializeComponent();
            addEventHandlers();
            setupToolTip();
            this.HandleDestroyed += new EventHandler(Conf_DBBrowser_HandleDestroyed);
            emuComboBox.SelectedIndexChanged += new EventHandler(emuComboBox_SelectedIndexChanged);
        }

        void clearPanel()
        {
            removeEventHandlers();

            idLabel.Text = "";

            lblPath.Text = "";
            txt_Title.Text = "";
            txt_company.Text = "";
            txt_description.Text = "";
            txt_yearmade.Text = "";
            txt_genre.Text = "";
            gradeUpDown.Value = 0;
            txt_Manual.Text = "";

            chk_Visible.Checked = false;
            chk_Favourite.Checked = false;

            label14.Text = "";
            playCountLabel.Text = "";
            lastPlayLabel.Text = "";

            profileComboBox.Items.Clear();

            pnlBoxFront.BackgroundImage = null;
            pnlBoxBack.BackgroundImage = null;
            pnlTitleScreen.BackgroundImage = null;
            pnlInGameScreen.BackgroundImage = null;
            pnlFanart.BackgroundImage = null;

            addEventHandlers();

            if (itemThumbs != null)
            {
                itemThumbs.Dispose();
                itemThumbs = null;
            }
            setGameArt();
        }

        void setGameArt()
        {
            pnlBoxFront.ThumbGroup = itemThumbs;
            pnlBoxBack.ThumbGroup = itemThumbs;
            pnlTitleScreen.ThumbGroup = itemThumbs;
            pnlInGameScreen.ThumbGroup = itemThumbs;
            pnlFanart.ThumbGroup = itemThumbs;
        }

        #region Event Handlers

        void Conf_DBBrowser_HandleDestroyed(object sender, EventArgs e)
        {
            close();
        }

        void Conf_DBBrowser_Load(object sender, EventArgs e)
        {
        }

        void onItemChanged(object sender, EventArgs e)
        {
            saveSelectedGame = true;
        }

        void onThumbChanged(object sender, EventArgs e)
        {
            saveThumbs = true;
        }

        void addEventHandlers()
        {
            dBListView.ItemSelectionChanged += new ListViewItemSelectionChangedEventHandler(dBListView_ItemSelectionChanged);
            txt_Title.TextChanged += new EventHandler(onItemChanged);
            txt_company.TextChanged += new EventHandler(onItemChanged);
            txt_description.TextChanged += new EventHandler(onItemChanged);
            txt_genre.TextChanged += new EventHandler(onItemChanged);
            txt_yearmade.TextChanged += new EventHandler(onItemChanged);
            txt_Manual.TextChanged += new EventHandler(onItemChanged);
            gradeUpDown.ValueChanged += new EventHandler(onItemChanged);

            chk_Visible.CheckedChanged += new EventHandler(onItemChanged);
            chk_Favourite.CheckedChanged += new EventHandler(onItemChanged);

            profileComboBox.SelectedIndexChanged += new EventHandler(onItemChanged);

            pnlBoxFront.BackgroundImageChanged += new EventHandler(onThumbChanged);
            pnlBoxBack.BackgroundImageChanged += new EventHandler(onThumbChanged);
            pnlTitleScreen.BackgroundImageChanged += new EventHandler(onThumbChanged);
            pnlInGameScreen.BackgroundImageChanged += new EventHandler(onThumbChanged);
            pnlFanart.BackgroundImageChanged += new EventHandler(onThumbChanged);
        }

        void removeEventHandlers()
        {
            dBListView.ItemSelectionChanged -= new ListViewItemSelectionChangedEventHandler(dBListView_ItemSelectionChanged);
            txt_Title.TextChanged -= new EventHandler(onItemChanged);
            txt_company.TextChanged -= new EventHandler(onItemChanged);
            txt_description.TextChanged -= new EventHandler(onItemChanged);
            txt_genre.TextChanged -= new EventHandler(onItemChanged);
            txt_yearmade.TextChanged -= new EventHandler(onItemChanged);
            txt_Manual.TextChanged -= new EventHandler(onItemChanged);
            gradeUpDown.ValueChanged -= new EventHandler(onItemChanged);

            chk_Visible.CheckedChanged -= new EventHandler(onItemChanged);
            chk_Favourite.CheckedChanged -= new EventHandler(onItemChanged);

            profileComboBox.SelectedIndexChanged -= new EventHandler(onItemChanged);

            pnlBoxFront.BackgroundImageChanged -= new EventHandler(onThumbChanged);
            pnlBoxBack.BackgroundImageChanged -= new EventHandler(onThumbChanged);
            pnlTitleScreen.BackgroundImageChanged -= new EventHandler(onThumbChanged);
            pnlInGameScreen.BackgroundImageChanged -= new EventHandler(onThumbChanged);
            pnlFanart.BackgroundImageChanged -= new EventHandler(onThumbChanged);
        }
        
        #endregion
        
        #region Database ListView

        volatile bool listLoading = false;
        void initListView()
        {
            if (listLoading)
                return;

            listLoading = true;

            dbGames = new List<ListViewItem>();

            loadingRomsPanel.Visible = true;
            dBListView.BeginUpdate();
            dBListView.Items.Clear();
            dBListView.EndUpdate();

            Thread thread = new Thread(new ThreadStart(delegate()
            {
                Game[] games = DB.Instance.GetGames();

                List<ListViewItem> newItems = new List<ListViewItem>();

                for (int x = 0; x < games.Length; x++)
                {
                    if (games[x].IsInfoChecked) //don't add games currently importing
                    {
                        ListViewItem item = new ListViewItem(games[x].Title);
                        item.Tag = games[x];
                        newItems.Add(item);
                    }
                }

                try
                {
                    BeginInvoke(new MethodInvoker(delegate
                    {
                        dbGames = newItems;
                        updateEmuBox(); //emu dropdown will handle list population
                        loadingRomsPanel.Visible = false;
                        listLoading = false;
                    }
                        ));
                }
                catch { listLoading = false; }
            }
            ));

            thread.Name = "Rom browser populator";
            thread.Start();
        }

        void dBListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            //if no items are selected, or we have just started selecting multiple items, clear the panel.
            //With multiple selections, only call the below code on the 2nd selection otherwise it will be
            //called for every new item added - which is unnecessary and expensive. 
            if (dBListView.SelectedItems.Count == 2)
            {
                selectedGame = null;
                selectedListItem = null;
                if (itemThumbs != null)
                {
                    itemThumbs.Dispose();
                    itemThumbs = null;
                }
                clearPanel();
                return;
            }

            //When the user changes selection in the list view the SelectionChanged event is fired twice,
            //once for the item losing selection and once for the item gaining it, ensure we only
            //update once.
            if (!e.IsSelected || dBListView.SelectedItems.Count > 1)
                return;

            updateGame();

            selectedListItem = dBListView.SelectedItems[0];
            setRomToPanel(selectedListItem);
        }

        //update panel with Game info
        void setRomToPanel(ListViewItem listViewItem)
        {
            saveSelectedGame = false;
            saveThumbs = false;
            Game dbRom = listViewItem.Tag as Game;
            selectedGame = dbRom;

            if (dbRom == null)
                return;

            removeEventHandlers();

            //update ThumbGroup
            if (itemThumbs != null)
                itemThumbs.Dispose();
            itemThumbs = new ThumbGroup(dbRom);

            setGameArt(); //load thumbs to panels

            idLabel.Text = dbRom.GameID.ToString();

            lblPath.Text = dbRom.Path;
            txt_Title.Text = dbRom.Title;
            txt_company.Text = dbRom.Company;
            txt_description.Text = dbRom.Description;
            txt_yearmade.Text = dbRom.Yearmade.ToString();
            txt_genre.Text = dbRom.Genre;
            gradeUpDown.Value = dbRom.Grade;

            txt_Manual.Text = itemThumbs.ManualPath;

            chk_Visible.Checked = dbRom.Visible;
            chk_Favourite.Checked = dbRom.Favourite;

            playCountLabel.Text = dbRom.Playcount.ToString();
            lastPlayLabel.Text = dbRom.Latestplay.ToShortDateString();

            profileComboBox.Items.Clear();
            bool selected = false;
            foreach (EmulatorProfile profile in DB.Instance.GetProfiles(dbRom.ParentEmulator))
            {
                profileComboBox.Items.Add(profile);
                if (!selected && profile.ID == dbRom.SelectedProfile)
                {
                    profileComboBox.SelectedItem = profile; //select Game profile
                    selected = true;
                }
            }

            //profile no longer exists, select default
            if (!selected && profileComboBox.Items.Count > 0)
            {
                profileComboBox.SelectedItem = profileComboBox.Items[0];
                saveSelectedGame = true; //remove reference to deleted profile for tidiness
            }

            addEventHandlers();
        }

        //update Game with panel info and Commit
        void updateGame()
        {
            updateThumbs();

            if (!saveSelectedGame || selectedGame == null)
                return;
            
            selectedGame.Title = txt_Title.Text;
            if (selectedListItem != null)
                selectedListItem.Text = selectedGame.Title;

            selectedGame.Company = txt_company.Text;
            selectedGame.Description = txt_description.Text;
            selectedGame.Genre = txt_genre.Text;
            try
            {
                selectedGame.Yearmade = Convert.ToInt32(txt_yearmade.Text);
            }
            catch
            {
                selectedGame.Yearmade = 0;
            }

            selectedGame.Grade = Convert.ToInt32(gradeUpDown.Value);

            selectedGame.Visible = chk_Visible.Checked;
            selectedGame.Favourite = chk_Favourite.Checked;

            EmulatorProfile selectedProfile = profileComboBox.SelectedItem as EmulatorProfile;
            if (selectedProfile != null)
                selectedGame.SelectedProfile = selectedProfile.ID;

            selectedGame.Save();

            if (itemThumbs != null)
            {
                itemThumbs.ManualPath = txt_Manual.Text;
                itemThumbs.SaveManual();
            }

            saveSelectedGame = false;
        }

        //save all thumbs
        void updateThumbs()
        {
            if (!saveThumbs || itemThumbs == null)
                return;

            itemThumbs.SaveAllThumbs();
            saveThumbs = false;
        }

        #endregion
                      
        #region Overrides

        public override void save()
        {
            updateGame();
            base.save();
        }

        public override void close()
        {
            save(); //otherwise game is not saved when closing as List selection not changed
            if (itemThumbs != null)
                itemThumbs.Dispose();
        }

        public override void update()
        {
            updateGame();
            initListView();
            base.update();
        }

        #endregion

        #region Emulator Dropdown

        private void updateEmuBox()
        {
            int prevSelected = -2;
            if (emuComboBox.SelectedItem != null)
            {
                prevSelected = ((ComboBoxItem)emuComboBox.SelectedItem).ID;
            }

            emuComboBox.SelectedIndexChanged -= new EventHandler(emuComboBox_SelectedIndexChanged);

            emuComboBox.BeginUpdate();
            emuComboBox.Items.Clear();
            emuComboBox.Items.AddRange(Dropdowns.GetEmuComboBoxItems());

            bool found = false;
            if (prevSelected != -2)
            {
                for (int x = 0; x < emuComboBox.Items.Count; x++)
                {
                    if (((ComboBoxItem)emuComboBox.Items[x]).ID == prevSelected)
                    {
                        emuComboBox.SelectedIndex = x;
                        found = true;
                        break;
                    }
                }
            }

            if (!found && emuComboBox.Items.Count > 0)
                emuComboBox.SelectedIndex = 0;

            emuComboBox.EndUpdate();
            emuComboBox.SelectedIndexChanged += new EventHandler(emuComboBox_SelectedIndexChanged);

            emuComboBox_SelectedIndexChanged(emuComboBox, new EventArgs());
        }

        void emuComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            updateGame();

            loadingRomsPanel.Visible = true;

            int id = -2;
            if (emuComboBox.SelectedItem != null)
                id = ((ComboBoxItem)emuComboBox.SelectedItem).ID;

            bool selected = false;
            int selectedGameID = -1;
            if (selectedListItem != null)
                selectedGameID = ((Game)selectedListItem.Tag).GameID;

            dBListView.BeginUpdate();
            dBListView.SelectedItems.Clear();
            dBListView.Items.Clear();

            for (int x = 0; x < dbGames.Count; x++)
            {
                Game game = (Game)dbGames[x].Tag;
                if (id == -2 || game.ParentEmulator.UID == id)
                {
                    dBListView.Items.Add(dbGames[x]);
                    if (selectedGameID != -1 && selectedGameID == game.GameID)
                    {
                        selected = true;
                        selectedListItem = dbGames[x];
                        dbGames[x].Selected = true;
                    }
                }
            }

            if (!selected)
            {
                if (dBListView.Items.Count > 0)
                {
                    selectedListItem = dBListView.Items[0];
                    dBListView.Items[0].Selected = true;
                }
            }

            dBListView.EndUpdate();
            loadingRomsPanel.Visible = false;
        }

        #endregion

        #region ToolTip

        void setupToolTip()
        {
            romToolTip.SetToolTip(launchRomButton, "Launch selected game");
            romToolTip.SetToolTip(sendToImportButton, "Send selected game(s) to importer");
            romToolTip.SetToolTip(getRomArtButton, "Update game artwork");
            romToolTip.SetToolTip(delRomButton, "Delete selected games(s)");
            romToolTip.SetToolTip(resetPlayCount, "Reset play count");
            romToolTip.SetToolTip(resetLastPlayed, "Reset last play date");
        }

        #endregion

        #region Buttons

        void launchRomButton_Click(object sender, EventArgs e)
        {
            updateGame();
            if (selectedGame != null)
                Executor.Instance.launchGame(selectedGame, true);
        }

        void sendToImportButton_Click(object sender, EventArgs e)
        {
            updateGame();

            List<Game> games = new List<Game>();
            foreach (ListViewItem item in dBListView.SelectedItems)
            {
                games.Add(item.Tag as Game);
            }

            sendToImporter(games.ToArray());

            dBListView.SelectedItems.Clear();

            update();
        }

        void sendToImporter(Game[] games)
        {
            Importer importer = Conf_GlobalSettings.Instance.Importer;

            Conf_ProgressDialog progressDlg = new Conf_ProgressDialog(games, new ProgressDialogDelegate(delegate(object item)
            {
                Game game = (Game)item;
                importer.AddGames(new Game[] { game });
                return string.Format("sending {0} to Importer", game.Title);
            }
                ));
            progressDlg.ShowDialog();
            progressDlg.Dispose();
        }

        void delRomButton_Click(object sender, EventArgs e)
        {
            if (dBListView.SelectedItems.Count == 0)
                return;

            DialogResult dlg = MessageBox.Show(
                "Are you sure you want to remove the selected Game(s) and add them to the ignored files list?", 
                "Delete Game(s)?", 
                MessageBoxButtons.YesNo);

            if (dlg != DialogResult.Yes)
                return;

            List<Game> games = new List<Game>();
            foreach (ListViewItem item in dBListView.SelectedItems)
                games.Add((Game)item.Tag);

            Importer importer = Conf_GlobalSettings.Instance.Importer;

            Conf_ProgressDialog progressDlg = new Conf_ProgressDialog(games.ToArray(), new ProgressDialogDelegate(delegate(object item)
            {
                Game game = (Game)item;
                importer.Remove(game.GameID);
                game.Delete();
                Options.Instance.AddIgnoreFile(game.Path);
                return "removing " + game.Title;
            }
            ));

            progressDlg.ShowDialog();
            progressDlg.Dispose();

            dBListView.SelectedItems.Clear();

            update();
        }

        void resetPlayCount_Click(object sender, EventArgs e)
        {
            if (selectedGame != null)
            {
                playCountLabel.Text = "0";
                selectedGame.Playcount = 0;
                saveSelectedGame = true;
            }
        }

        void resetLastPlayed_Click(object sender, EventArgs e)
        {
            if (selectedGame != null)
            {
                lastPlayLabel.Text = DateTime.MinValue.ToShortDateString();
                selectedGame.Latestplay = DateTime.MinValue;
                saveSelectedGame = true;
            }
        }

        #endregion

        Game newGame = null;

        private void addRomButton_Click(object sender, EventArgs e)
        {
            SuspendLayout();

            lblPath.Visible = false;
            dBListView.Enabled = false;
            addRomButton.Enabled = false;
            delRomButton.Enabled = false;
            emuComboBox.Enabled = false;
            launchRomButton.Enabled = false;
            sendToImportButton.Enabled = false;
            getRomArtButton.Enabled = false;
            profileComboBox.Items.Clear();
            profileComboBox.Enabled = false;

            newRomPathTextBox.Visible = true;
            romPathButton.Visible = true;

            int selectedEmu = -2;
            if (emuComboBox.SelectedItem != null)
                selectedEmu = ((ComboBoxItem)emuComboBox.SelectedItem).ID;

            newRomEmuComboBox.Items.Clear();
            bool selected = false;
            foreach (ComboBoxItem item in Dropdowns.GetNewRomComboBoxItems())
            {
                newRomEmuComboBox.Items.Add(item);
                if (item.ID == selectedEmu)
                {
                    newRomEmuComboBox.SelectedItem = item;
                    selected = true;
                }
            }
            if (!selected && newRomEmuComboBox.Items.Count > 0)
                newRomEmuComboBox.SelectedItem = newRomEmuComboBox.Items[0];

            newRomEmuComboBox.Visible = true;
            newGameGroupBox.Visible = true;

            selectedGame = null;
            saveThumbs = false;

            clearPanel();

            removeEventHandlers();

            newGame = new Game();
            itemThumbs = new ThumbGroup(newGame);
            setGameArt();

            ResumeLayout();
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            if (newGame == null || !validateNewGame())
                return;

            newGame.Path = newRomPathTextBox.Text;
            newGame.ParentEmulator = (Emulator)((ComboBoxItem)newRomEmuComboBox.SelectedItem).Value;
            newGame.Title = txt_Title.Text;
            newGame.Company = txt_company.Text;

            int year;
            if (!int.TryParse(txt_yearmade.Text, out year))
                year = 0;
            newGame.Yearmade = year;

            newGame.Grade = (int)gradeUpDown.Value;
            newGame.Genre = txt_genre.Text;
            newGame.Description = txt_description.Text;
            newGame.Visible = chk_Visible.Checked;
            newGame.Favourite = chk_Favourite.Checked;

            newGame.IsInfoChecked = !newGameImportCheckBox.Checked;

            newGame.Save();

            if (itemThumbs != null)
            {
                //create new thumbgroup now we know parent emulator, so thumbs are resized correctly
                using (ThumbGroup thumbs = new ThumbGroup(newGame))
                {
                    thumbs.FrontCover.Image = itemThumbs.FrontCover.Image;
                    thumbs.BackCover.Image = itemThumbs.BackCover.Image;
                    thumbs.TitleScreen.Image = itemThumbs.TitleScreen.Image;
                    thumbs.InGame.Image = itemThumbs.InGame.Image;
                    thumbs.Fanart.Image = itemThumbs.Fanart.Image;
                    thumbs.ManualPath = txt_Manual.Text;
                    thumbs.SaveManual();
                    thumbs.SaveAllThumbs();
                }
            }

            if (newGameImportCheckBox.Checked) //send to importer
            {
                sendToImporter(new Game[] { newGame });
            }
            else//if we're not sending to importer,
            {
                //set selectedListItem to new game so it will be selected after list refresh
                selectedListItem = new ListViewItem(newGame.Title) { Tag = newGame };
            }

            update(); //refresh list view 

            cancelButton_Click(this, new EventArgs());
        }

        private bool validateNewGame()
        {
            bool valid = true;
            string message = "Unable to save new game. Ensure the following actions are completed.";
            if (!System.IO.File.Exists(newRomPathTextBox.Text))
            {
                message += "\r\n\t- Provide a valid path to the game file";
                valid = false;
            }
            if (newRomEmuComboBox.SelectedItem == null)
            {
                message += "\r\n\t- Select the parent Emulator for the game";
                valid = false;
            }
            if (string.IsNullOrEmpty(txt_Title.Text))
            {
                message += "\r\n\t- Provide a title for the game";
                valid = false;
            }

            if (!valid)
                MessageBox.Show(message, "Unable to save new game", MessageBoxButtons.OK);

            return valid;
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.SuspendLayout();

            lblPath.Visible = true;
            dBListView.Enabled = true;
            addRomButton.Enabled = true;
            delRomButton.Enabled = true;
            emuComboBox.Enabled = true;
            launchRomButton.Enabled = true;
            sendToImportButton.Enabled = true;
            getRomArtButton.Enabled = true;
            profileComboBox.Enabled = true;

            newRomPathTextBox.Visible = false;
            newRomPathTextBox.Text = "";
            romPathButton.Visible = false;

            newRomEmuComboBox.Visible = false;
            newGameImportCheckBox.Checked = true;
            newGameGroupBox.Visible = false;

            this.ResumeLayout();

            addEventHandlers();

            dBListView.SelectedItems.Clear();
            if (selectedListItem != null)
                selectedListItem.Selected = true;
            else if (dBListView.Items.Count > 0)
                dBListView.Items[0].Selected = true;
        }

        private void btnNewManual_Click(object sender, EventArgs e)
        {
            string filter = "PDF | *.pdf";

            string initialDirectory;
            if (txt_Manual.Text != "" && txt_Manual.Text.LastIndexOf("\\") > -1)
                initialDirectory = txt_Manual.Text.Remove(txt_Manual.Text.LastIndexOf("\\"));
            else
                initialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            using (OpenFileDialog dlg = Conf_GlobalSettings.OpenFileDialog("Select manual", filter, initialDirectory))
            {
                if (dlg.ShowDialog() == DialogResult.OK)
                    txt_Manual.Text = dlg.FileName;
            }
        }

        private void btnManual_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txt_Manual.Text))
                return;

            if (!txt_Manual.Text.ToLower().EndsWith(".pdf") || !System.IO.File.Exists(txt_Manual.Text))
                return;

            using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
            {
                proc.StartInfo = new System.Diagnostics.ProcessStartInfo(txt_Manual.Text);
                proc.Start();
            }
        }

        private void romPathButton_Click(object sender, EventArgs e)
        {
            string filter = "All files (*.*) | *.*";

            string initialDirectory;
            int index = newRomPathTextBox.Text.LastIndexOf("\\");

            if (index > -1)
                initialDirectory = newRomPathTextBox.Text.Remove(index);
            else
                initialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            using (OpenFileDialog dlg = Conf_GlobalSettings.OpenFileDialog("Select path to emulator", filter, initialDirectory))
            {
                if (dlg.ShowDialog() == DialogResult.OK)
                    newRomPathTextBox.Text = dlg.FileName;
            }
        }

        private void getRomArtButton_Click(object sender, EventArgs e)
        {
            if (selectedGame == null)
                return;

            Conf_GlobalSettings.Instance.ShowThumbRetriever(selectedGame);
        }

    }
}
